home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / HTTP / Upload.php < prev   
PHP Script  |  2004-10-01  |  32KB  |  856 lines

  1. <?php
  2. // **********************************************
  3. //
  4. // This software is licensed by the LGPL
  5. // -> http://www.gnu.org/copyleft/lesser.txt
  6. // (c) 2001-2004 by Tomas Von Veschler Cox
  7. //
  8. // **********************************************
  9. //
  10. // $Id: Upload.php,v 1.42 2004/08/08 09:37:50 wenz Exp $
  11.  
  12. /*
  13.  * Pear File Uploader class. Easy and secure managment of files
  14.  * submitted via HTML Forms.
  15.  *
  16.  * Leyend:
  17.  * - you can add error msgs in your language in the HTTP_Upload_Error class
  18.  *
  19.  * TODO:
  20.  * - try to think a way of having all the Error system in other
  21.  *   file and only include it when an error ocurrs
  22.  *
  23.  * -- Notes for users HTTP_Upload >= 0.9.0 --
  24.  *
  25.  *  Error detection was enhanced, so you no longer need to
  26.  *  check for PEAR::isError() in $upload->getFiles() or call
  27.  *  $upload->isMissing(). Instead you'll
  28.  *  get the error when do a check for $file->isError().
  29.  *
  30.  *  Example:
  31.  *
  32.  *  $upload = new HTTP_Upload('en');
  33.  *  $file = $upload->getFiles('i_dont_exist_in_form_definition');
  34.  *  if ($file->isError()) {
  35.  *      die($file->getMessage());
  36.  *  }
  37.  *
  38.  *  --
  39.  *
  40.  */
  41.  
  42. require_once 'PEAR.php';
  43.  
  44. /**
  45.  * defines default chmod
  46.  */
  47. define('HTTP_UPLOAD_DEFAULT_CHMOD', 0660);
  48.  
  49. /**
  50.  * Error Class for HTTP_Upload
  51.  *
  52.  * @author  Tomas V.V.Cox <cox@idecnet.com>
  53.  * @see http://vulcanonet.com/soft/index.php?pack=uploader
  54.  * @package HTTP_Upload
  55.  * @category HTTP
  56.  * @access public
  57.  */
  58. class HTTP_Upload_Error extends PEAR
  59. {
  60.     /**
  61.      * Selected language for error messages
  62.      * @var string
  63.      */
  64.     var $lang = 'en';
  65.  
  66.     /**
  67.      * Whether HTML entities shall be encoded automatically
  68.      * @var boolean
  69.      */
  70.     var $html = false;
  71.  
  72.     /**
  73.      * Constructor
  74.      *
  75.      * Creates a new PEAR_Error
  76.      *
  77.      * @param string $lang The language selected for error code messages
  78.      * @access public
  79.      */
  80.     function HTTP_Upload_Error($lang = null, $html = false)
  81.     {
  82.         $this->lang = ($lang !== null) ? $lang : $this->lang;
  83.         $this->html = ($html !== false) ? $html : $this->html;
  84.         $ini_size = preg_replace('/m/i', '000000', ini_get('upload_max_filesize'));
  85.  
  86.         if (function_exists('version_compare') &&
  87.             version_compare(phpversion(), '4.1', 'ge')) {
  88.             $maxsize = (isset($_POST['MAX_FILE_SIZE'])) ?
  89.                 $_POST['MAX_FILE_SIZE'] : null;
  90.         } else {
  91.             global $HTTP_POST_VARS;
  92.             $maxsize = (isset($HTTP_POST_VARS['MAX_FILE_SIZE'])) ?
  93.                 $HTTP_POST_VARS['MAX_FILE_SIZE'] : null;
  94.         }
  95.  
  96.         if (empty($maxsize) || ($maxsize > $ini_size)) {
  97.             $maxsize = $ini_size;
  98.         }
  99.         // XXXXX Add here error messages in your language
  100.         $this->error_codes = array(
  101.             'TOO_LARGE' => array(
  102.                 'es'    => "Fichero demasiado largo. El maximo permitido es: $maxsize bytes.",
  103.                 'en'    => "File size too large. The maximum permitted size is: $maxsize bytes.",
  104.                 'de'    => "Datei zu groß. Die zulässige Maximalgröße ist: $maxsize Bytes.",
  105.                 'nl'    => "Het bestand is te groot, de maximale grootte is: $maxsize bytes.",
  106.                 'fr'    => "Le fichier est trop gros. La taille maximum autorisée est: $maxsize bytes.",
  107.                 'it'    => "Il file é troppo grande. Il massimo permesso é: $maxsize bytes.",
  108.                 'pt_BR' => "Arquivo muito grande. O tamanho máximo permitido é $maxsize bytes."
  109.                 ),
  110.             'MISSING_DIR' => array(
  111.                 'es'    => 'Falta directorio destino.',
  112.                 'en'    => 'Missing destination directory.',
  113.                 'de'    => 'Kein Zielverzeichnis definiert.',
  114.                 'nl'    => 'Geen bestemmings directory.',
  115.                 'fr'    => 'Le répertoire de destination n\'est pas défini.',
  116.                 'it'    => 'Manca la directory di destinazione.',
  117.                 'pt_BR' => 'Ausência de diretório de destino.'
  118.                 ),
  119.             'IS_NOT_DIR' => array(
  120.                 'es'    => 'El directorio destino no existe o es un fichero regular.',
  121.                 'en'    => 'The destination directory doesn\'t exist or is a regular file.',
  122.                 'de'    => 'Das angebene Zielverzeichnis existiert nicht oder ist eine Datei.',
  123.                 'nl'    => 'De doeldirectory bestaat niet, of is een gewoon bestand.',
  124.                 'fr'    => 'Le répertoire de destination n\'existe pas ou il s\'agit d\'un fichier régulier.',
  125.                 'it'    => 'La directory di destinazione non esiste o é un file.',
  126.                 'pt_BR' => 'O diretório de destino não existe ou é um arquivo.'
  127.                 ),
  128.             'NO_WRITE_PERMS' => array(
  129.                 'es'    => 'El directorio destino no tiene permisos de escritura.',
  130.                 'en'    => 'The destination directory doesn\'t have write perms.',
  131.                 'de'    => 'Fehlende Schreibrechte für das Zielverzeichnis.',
  132.                 'nl'    => 'Geen toestemming om te schrijven in de doeldirectory.',
  133.                 'fr'    => 'Le répertoire de destination n\'a pas les droits en écriture.',
  134.                 'it'    => 'Non si hanno i permessi di scrittura sulla directory di destinazione.',
  135.                 'pt_BR' => 'O diretório de destino não possui permissão para escrita.'
  136.                 ),
  137.             'NO_USER_FILE' => array(
  138.                 'es'    => 'No se ha escogido fichero para el upload.',
  139.                 'en'    => 'You haven\'t selected any file for uploading.',
  140.                 'de'    => 'Es wurde keine Datei für den Upload ausgewählt.',
  141.                 'nl'    => 'Er is geen bestand opgegeven om te uploaden.',
  142.                 'fr'    => 'Vous n\'avez pas sélectionné de fichier à envoyer.',
  143.                 'it'    => 'Nessun file selezionato per l\'upload.',
  144.                 'pt_BR' => 'Nenhum arquivo selecionado para upload.'
  145.                 ),
  146.             'BAD_FORM' => array(
  147.                 'es'    => 'El formulario no contiene method="post" enctype="multipart/form-data" requerido.',
  148.                 'en'    => 'The html form doesn\'t contain the required method="post" enctype="multipart/form-data".',
  149.                 'de'    => 'Das HTML-Formular enthält nicht die Angabe method="post" enctype="multipart/form-data" '.
  150.                            'im >form<-Tag.',
  151.                 'nl'    => 'Het HTML-formulier bevat niet de volgende benodigde '.
  152.                            'eigenschappen: method="post" enctype="multipart/form-data".',
  153.                 'fr'    => 'Le formulaire HTML ne contient pas les attributs requis : '.
  154.                            ' method="post" enctype="multipart/form-data".',
  155.                 'it'    => 'Il modulo HTML non contiene gli attributi richiesti: "'.
  156.                            ' method="post" enctype="multipart/form-data".',
  157.                 'pt_BR' => 'O formulário HTML não possui o method="post" enctype="multipart/form-data" requerido.'
  158.                 ),
  159.             'E_FAIL_COPY' => array(
  160.                 'es'    => 'Fallo al copiar el fichero temporal.',
  161.                 'en'    => 'Failed to copy the temporary file.',
  162.                 'de'    => 'Temporäre Datei konnte nicht kopiert werden.',
  163.                 'nl'    => 'Het tijdelijke bestand kon niet gekopieerd worden.',
  164.                 'fr'    => 'L\'enregistrement du fichier temporaire a échoué.',
  165.                 'it'    => 'Copia del file temporaneo fallita.',
  166.                 'pt_BR' => 'Falha ao copiar o arquivo temporário.'
  167.                 ),
  168.             'E_FAIL_MOVE' => array(
  169.                 'es'    => 'No puedo mover el fichero.',
  170.                 'en'    => 'Impossible to move the file.',
  171.                 'de'    => 'Datei kann nicht verschoben werden.',
  172.                 'nl'    => 'Het bestand kon niet verplaatst worden.',
  173.                 'fr'    => 'Impossible de déplacer le fichier.',
  174.                 'pt_BR' => 'Não foi possível mover o arquivo.'
  175.                 ),
  176.             'FILE_EXISTS' => array(
  177.                 'es'    => 'El fichero destino ya existe.',
  178.                 'en'    => 'The destination file already exists.',
  179.                 'de'    => 'Die zu erzeugende Datei existiert bereits.',
  180.                 'nl'    => 'Het doelbestand bestaat al.',
  181.                 'fr'    => 'Le fichier de destination existe déjà.',
  182.                 'it'    => 'File destinazione già esistente.',
  183.                 'pt_BR' => 'O arquivo de destino já existe.'
  184.                 ),
  185.             'CANNOT_OVERWRITE' => array(
  186.                 'es'    => 'El fichero destino ya existe y no se puede sobreescribir.',
  187.                 'en'    => 'The destination file already exists and could not be overwritten.',
  188.                 'de'    => 'Die zu erzeugende Datei existiert bereits und konnte nicht überschrieben werden.',
  189.                 'nl'    => 'Het doelbestand bestaat al, en kon niet worden overschreven.',
  190.                 'fr'    => 'Le fichier de destination existe déjà et ne peux pas être remplacé.',
  191.                 'it'    => 'File destinazione già esistente e non si può sovrascrivere.',
  192.                 'pt_BR' => 'O arquivo de destino já existe e não pôde ser sobrescrito.'
  193.                 ),
  194.             'NOT_ALLOWED_EXTENSION' => array(
  195.                 'es'    => 'Extension de fichero no permitida.',
  196.                 'en'    => 'File extension not permitted.',
  197.                 'de'    => 'Unerlaubte Dateiendung.',
  198.                 'nl'    => 'Niet toegestane bestands-extensie.',
  199.                 'fr'    => 'Le fichier a une extension non autorisée.',
  200.                 'it'    => 'Estensione del File non permessa.',
  201.                 'pt_BR' => 'Extensão de arquivo não permitida.'
  202.                 ),
  203.             'PARTIAL' => array(
  204.                 'es'    => 'El fichero fue parcialmente subido',
  205.                 'en'    => 'The file was only partially uploaded.',
  206.                 'de'    => 'Die Datei wurde unvollständig übertragen.',
  207.                 'nl'    => 'Het bestand is slechts gedeeltelijk geupload.',
  208.                 'pt_BR' => 'O arquivo nπo foi enviado por completo.'
  209.                 ),
  210.             'ERROR' => array(
  211.                 'es'    => 'Error en subida:',
  212.                 'en'    => 'Upload error:',
  213.                 'de'    => 'Fehler beim Upload:',
  214.                 'nl'    => 'Upload fout:',
  215.                 'pt_BR' => 'Erro de upload:'
  216.                 ),
  217.             'DEV_NO_DEF_FILE' => array(
  218.                 'es'    => 'No estß definido en el formulario este nombre de fichero como <input type="file" name=?>.',
  219.                 'en'    => 'This filename is not defined in the form as <input type="file" name=?>.',
  220.                 'de'    => 'Dieser Dateiname ist im Formular nicht als <input type="file" name=?> definiert.',
  221.                 'nl'    => 'Deze bestandsnaam is niett gedefineerd in het formulier als <input type="file" name=?>.'
  222.                 )
  223.         );
  224.     }
  225.  
  226.     /**
  227.      * returns the error code
  228.      *
  229.      * @param    string $e_code  type of error
  230.      * @return   string          Error message
  231.      */
  232.     function errorCode($e_code)
  233.     {
  234.         if (!empty($this->error_codes[$e_code][$this->lang])) {
  235.             $msg = $this->html ?
  236.                 html_entity_decode($this->error_codes[$e_code][$this->lang]) :
  237.                 $this->error_codes[$e_code][$this->lang];
  238.         } else {
  239.             $msg = $e_code;
  240.         }
  241.  
  242.         if (!empty($this->error_codes['ERROR'][$this->lang])) {
  243.             $error = $this->error_codes['ERROR'][$this->lang];
  244.         } else {
  245.             $error = $this->error_codes['ERROR']['en'];
  246.         }
  247.         return $error.' '.$msg;
  248.     }
  249.  
  250.     /**
  251.      * Overwrites the PEAR::raiseError method
  252.      *
  253.      * @param    string $e_code      type of error
  254.      * @return   object PEAR_Error   a PEAR-Error object
  255.      * @access   public
  256.      */
  257.     function raiseError($e_code)
  258.     {
  259.         return PEAR::raiseError($this->errorCode($e_code), $e_code);
  260.     }
  261. }
  262.  
  263. /**
  264.  * This class provides an advanced file uploader system
  265.  * for file uploads made from html forms
  266.  
  267.  *
  268.  * @author  Tomas V.V.Cox <cox@idecnet.com>
  269.  * @see http://vulcanonet.com/soft/index.php?pack=uploader
  270.  * @package  HTTP_Upload
  271.  * @category HTTP
  272.  * @access   public
  273.  */
  274. class HTTP_Upload extends HTTP_Upload_Error
  275. {
  276.     /**
  277.      * Contains an array of "uploaded files" objects
  278.      * @var array
  279.      */
  280.     var $files = array();
  281.     
  282.     /**
  283.      * Contains the desired chmod for uploaded files
  284.      * @var int
  285.      * @access private
  286.      */
  287.     var $_chmod = HTTP_UPLOAD_DEFAULT_CHMOD;
  288.  
  289.     /**
  290.      * Constructor
  291.      *
  292.      * @param string $lang Language to use for reporting errors
  293.      * @see Upload_Error::error_codes
  294.      * @access public
  295.      */
  296.     function HTTP_Upload($lang = null)
  297.     {
  298.         $this->HTTP_Upload_Error($lang);
  299.         if (function_exists('version_compare') &&
  300.             version_compare(phpversion(), '4.1', 'ge'))
  301.         {
  302.             $this->post_files = $_FILES;
  303.             if (isset($_SERVER['CONTENT_TYPE'])) {
  304.                 $this->content_type = $_SERVER['CONTENT_TYPE'];
  305.             }
  306.         } else {
  307.             global $HTTP_POST_FILES, $HTTP_SERVER_VARS;
  308.             $this->post_files = $HTTP_POST_FILES;
  309.             if (isset($HTTP_SERVER_VARS['CONTENT_TYPE'])) {
  310.                 $this->content_type = $HTTP_SERVER_VARS['CONTENT_TYPE'];
  311.             }
  312.         }
  313.     }
  314.  
  315.     /**
  316.      * Get files
  317.      *
  318.      * @param mixed $file If:
  319.      *    - not given, function will return array of upload_file objects
  320.      *    - is int, will return the $file position in upload_file objects array
  321.      *    - is string, will return the upload_file object corresponding
  322.      *        to $file name of the form. For ex:
  323.      *        if form is <input type="file" name="userfile">
  324.      *        to get this file use: $upload->getFiles('userfile')
  325.      *
  326.      * @return mixed array or object (see @param $file above) or Pear_Error
  327.      * @access public
  328.      */
  329.     function &getFiles($file = null)
  330.     {
  331.         static $is_built = false;
  332.         //build only once for multiple calls
  333.         if (!$is_built) {
  334.             $files = &$this->_buildFiles();
  335.             if (PEAR::isError($files)) {
  336.                 // there was an error with the form.
  337.                 // Create a faked upload embedding the error
  338.                 $this->files['_error'] =  &new HTTP_Upload_File(
  339.                                                        '_error', null,
  340.                                                        null, null,
  341.                                                        null, $files->getCode(),
  342.                                                        $this->lang, $this->_chmod);
  343.             } else {
  344.                 $this->files = $files;
  345.             }
  346.             $is_built = true;
  347.         }
  348.         if ($file !== null) {
  349.             if (is_int($file)) {
  350.                 $pos = 0;
  351.                 foreach ($this->files as $obj) {
  352.                     if ($pos == $file) {
  353.                         return $obj;
  354.                     }
  355.                     $pos++;
  356.                 }
  357.             } elseif (is_string($file) && isset($this->files[$file])) {
  358.                 return $this->files[$file];
  359.             }
  360.             if (isset($this->files['_error'])) {
  361.                 return $this->files['_error'];
  362.             } else {
  363.                 // developer didn't specify this name in the form
  364.                 // warn him about it with a faked upload
  365.                 return new HTTP_Upload_File(
  366.                                            '_error', null,
  367.                                            null, null,
  368.                                            null, 'DEV_NO_DEF_FILE',
  369.                                            $this->lang);
  370.             }
  371.         }
  372.         return $this->files;
  373.     }
  374.  
  375.     /**
  376.      * Creates the list of the uploaded file
  377.      *
  378.      * @return array of HTTP_Upload_File objects for every file
  379.      */
  380.     function &_buildFiles()
  381.     {
  382.         // Form method check
  383.         if (!isset($this->content_type) ||
  384.             strpos($this->content_type, 'multipart/form-data') !== 0)
  385.         {
  386.             return $this->raiseError('BAD_FORM');
  387.         }
  388.         // In 4.1 $_FILES isn't initialized when no uploads
  389.         // XXX (cox) afaik, in >= 4.1 and <= 4.3 only
  390.         if (function_exists('version_compare') &&
  391.             version_compare(phpversion(), '4.1', 'ge'))
  392.         {
  393.             $error = $this->isMissing();
  394.             if (PEAR::isError($error)) {
  395.                 return $error;
  396.             }
  397.         }
  398.  
  399.         // map error codes from 4.2.0 $_FILES['userfile']['error']
  400.         if (function_exists('version_compare') &&
  401.             version_compare(phpversion(), '4.2.0', 'ge')) {
  402.             $uploadError = array(
  403.                 1 => 'TOO_LARGE',
  404.                 2 => 'TOO_LARGE',
  405.                 3 => 'PARTIAL',
  406.                 4 => 'NO_USER_FILE'
  407.                 );
  408.         }
  409.  
  410.  
  411.         // Parse $_FILES (or $HTTP_POST_FILES)
  412.         $files = array();
  413.         foreach ($this->post_files as $userfile => $value) {
  414.             if (is_array($value['name'])) {
  415.                 foreach ($value['name'] as $key => $val) {
  416.                     $err = $value['error'][$key];
  417.                     if (isset($err) && $err !== 0 && isset($uploadError[$err])) {
  418.                         $error = $uploadError[$err];
  419.                     } else {
  420.                         $error = null;
  421.                     }
  422.                     $name = basename($value['name'][$key]);
  423.                     $tmp_name = $value['tmp_name'][$key];
  424.                     $size = $value['size'][$key];
  425.                     $type = $value['type'][$key];
  426.                     $formname = $userfile . "[$key]";
  427.                     $files[$formname] = new HTTP_Upload_File($name, $tmp_name,
  428.                                                              $formname, $type, $size, $error, $this->lang, $this->_chmod);
  429.                 }
  430.                 // One file
  431.             } else {
  432.                 $err = $value['error'];
  433.                 if (isset($err) && $err !== 0 && isset($uploadError[$err])) {
  434.                     $error = $uploadError[$err];
  435.                 } else {
  436.                     $error = null;
  437.                 }
  438.                 $name = basename($value['name']);
  439.                 $tmp_name = $value['tmp_name'];
  440.                 $size = $value['size'];
  441.                 $type = $value['type'];
  442.                 $formname = $userfile;
  443.                 $files[$formname] = new HTTP_Upload_File($name, $tmp_name,
  444.                                                          $formname, $type, $size, $error, $this->lang, $this->_chmod);
  445.             }
  446.         }
  447.         return $files;
  448.     }
  449.  
  450.     /**
  451.      * Checks if the user submited or not some file
  452.      *
  453.      * @return mixed False when are files or PEAR_Error when no files
  454.      * @access public
  455.      * @see Read the note in the source code about this function
  456.      */
  457.     function isMissing()
  458.     {
  459.         if (count($this->post_files) < 1) {
  460.             return $this->raiseError('NO_USER_FILE');
  461.         }
  462.         //we also check if at least one file has more than 0 bytes :)
  463.         $files = array();
  464.         $size = 0;
  465.         foreach ($this->post_files as $userfile => $value) {
  466.             if (is_array($value['name'])) {
  467.                 foreach ($value['name'] as $key => $val) {
  468.                     $size += $value['size'][$key];
  469.                 }
  470.             } else {  //one file
  471.                 $size = $value['size'];
  472.             }
  473.         }
  474.         if ($size == 0) {
  475.             $this->raiseError('NO_USER_FILE');
  476.         }
  477.         return false;
  478.     }
  479.  
  480.     /**
  481.      * Sets the chmod to be used for uploaded files
  482.      *
  483.      * @param int Desired mode 
  484.      */
  485.     function setChmod($mode)
  486.     {
  487.         $this->_chmod = $mode;
  488.     }
  489. }
  490.  
  491. /**
  492.  * This class provides functions to work with the uploaded file
  493.  *
  494.  * @author  Tomas V.V.Cox <cox@idecnet.com>
  495.  * @see http://vulcanonet.com/soft/index.php?pack=uploader
  496.  * @package  HTTP_Upload
  497.  * @category HTTP
  498.  * @access   public
  499.  */
  500. class HTTP_Upload_File extends HTTP_Upload_Error
  501. {
  502.     /**
  503.      * If the random seed was initialized before or not
  504.      * @var  boolean;
  505.      */
  506.     var $_seeded = 0;
  507.  
  508.     /**
  509.      * Assoc array with file properties
  510.      * @var array
  511.      */
  512.     var $upload = array();
  513.  
  514.     /**
  515.      * If user haven't selected a mode, by default 'safe' will be used
  516.      * @var boolean
  517.      */
  518.     var $mode_name_selected = false;
  519.  
  520.     /**
  521.      * It's a common security risk in pages who has the upload dir
  522.      * under the document root (remember the hack of the Apache web?)
  523.      *
  524.      * @var array
  525.      * @access private
  526.      * @see HTTP_Upload_File::setValidExtensions()
  527.      */
  528.     var $_extensions_check = array('php', 'phtm', 'phtml', 'php3', 'inc');
  529.  
  530.     /**
  531.      * @see HTTP_Upload_File::setValidExtensions()
  532.      * @var string
  533.      * @access private
  534.      */
  535.     var $_extensions_mode  = 'deny';
  536.  
  537.     /**
  538.      * Contains the desired chmod for uploaded files
  539.      * @var int
  540.      * @access private
  541.      */
  542.     var $_chmod = HTTP_UPLOAD_DEFAULT_CHMOD;
  543.  
  544.     /**
  545.      * Constructor
  546.      *
  547.      * @param   string  $name       destination file name
  548.      * @param   string  $tmp        temp file name
  549.      * @param   string  $formname   name of the form
  550.      * @param   string  $type       Mime type of the file
  551.      * @param   string  $size       size of the file
  552.      * @param   string  $error      error on upload
  553.      * @param   string  $lang       used language for errormessages
  554.      * @access  public
  555.      */
  556.     function HTTP_Upload_File($name = null, $tmp = null,  $formname = null,
  557.                               $type = null, $size = null, $error = null, 
  558.                               $lang = null, $chmod = HTTP_UPLOAD_DEFAULT_CHMOD)
  559.     {
  560.         $this->HTTP_Upload_Error($lang);
  561.         $ext = null;
  562.  
  563.         if (empty($name) || $size == 0) {
  564.             $error = 'NO_USER_FILE';
  565.         } elseif ($tmp == 'none') {
  566.             $error = 'TOO_LARGE';
  567.         } else {
  568.             // strpos needed to detect files without extension
  569.             if (($pos = strrpos($name, '.')) !== false) {
  570.                 $ext = substr($name, $pos + 1);
  571.             }
  572.         }
  573.  
  574.         if (function_exists('version_compare') &&
  575.             version_compare(phpversion(), '4.1', 'ge')) {
  576.             if (isset($_POST['MAX_FILE_SIZE']) &&
  577.                 $size > $_POST['MAX_FILE_SIZE']) {
  578.                 $error = 'TOO_LARGE';
  579.             }
  580.         } else {
  581.             global $HTTP_POST_VARS;
  582.             if (isset($HTTP_POST_VARS['MAX_FILE_SIZE']) &&
  583.                 $size > $HTTP_POST_VARS['MAX_FILE_SIZE']) {
  584.                 $error = 'TOO_LARGE';
  585.             }
  586.         }
  587.  
  588.         $this->upload = array(
  589.             'real'      => $name,
  590.             'name'      => $name,
  591.             'form_name' => $formname,
  592.             'ext'       => $ext,
  593.             'tmp_name'  => $tmp,
  594.             'size'      => $size,
  595.             'type'      => $type,
  596.             'error'     => $error
  597.         );
  598.  
  599.         $this->_chmod = $chmod;
  600.     }
  601.  
  602.     /**
  603.      * Sets the name of the destination file
  604.      *
  605.      * @param string $mode     A valid mode: 'uniq', 'safe' or 'real' or a file name
  606.      * @param string $prepend  A string to prepend to the name
  607.      * @param string $append   A string to append to the name
  608.      *
  609.      * @return string The modified name of the destination file
  610.      * @access public
  611.      */
  612.     function setName($mode, $prepend = null, $append = null)
  613.     {
  614.         switch ($mode) {
  615.             case 'uniq':
  616.                 $name = $this->nameToUniq();
  617.                 $this->upload['ext'] = $this->nameToSafe($this->upload['ext'], 10);
  618.                 $name .= '.' . $this->upload['ext'];
  619.                 break;
  620.             case 'safe':
  621.                 $name = $this->nameToSafe($this->upload['real']);
  622.                 if (($pos = strrpos($name, '.')) !== false) {
  623.                     $this->upload['ext'] = substr($name, $pos + 1);
  624.                 } else {
  625.                     $this->upload['ext'] = '';
  626.                 }
  627.                 break;
  628.             case 'real':
  629.                 $name = $this->upload['real'];
  630.                 break;
  631.             default:
  632.                 $name = $mode;
  633.         }
  634.         $this->upload['name'] = $prepend . $name . $append;
  635.         $this->mode_name_selected = true;
  636.         return $this->upload['name'];
  637.     }
  638.  
  639.     /**
  640.      * Unique file names in the form: 9022210413b75410c28bef.html
  641.      * @see HTTP_Upload_File::setName()
  642.      */
  643.     function nameToUniq()
  644.     {
  645.         if (! $this->_seeded) {
  646.             srand((double) microtime() * 1000000);
  647.             $this->_seeded = 1;
  648.         }
  649.         $uniq = uniqid(rand());
  650.         return $uniq;
  651.     }
  652.  
  653.     /**
  654.      * Format a file name to be safe
  655.      *
  656.      * @param    string $file   The string file name
  657.      * @param    int    $maxlen Maximun permited string lenght
  658.      * @return   string Formatted file name
  659.      * @see HTTP_Upload_File::setName()
  660.      */
  661.     function nameToSafe($name, $maxlen=250)
  662.     {
  663.         $noalpha = '┴╔═╙┌▌ßΘφ≤·²┬╩╬╘█ΓΩε⌠√└╚╠╥┘αΦ∞≥∙─╦╧╓▄Σδ∩÷ⁿ ├π╒⌡┼σ╤±╟τ@░║¬';
  664.         $alpha   = 'AEIOUYaeiouyAEIOUaeiouAEIOUaeiouAEIOUaeiouyAaOoAaNnCcaooa';
  665.  
  666.         $name = substr($name, 0, $maxlen);
  667.         $name = strtr($name, $noalpha, $alpha);
  668.         // not permitted chars are replaced with "_"
  669.         return preg_replace('/[^a-zA-Z0-9,._\+\()\-]/', '_', $name);
  670.     }
  671.  
  672.     /**
  673.      * The upload was valid
  674.      *
  675.      * @return bool If the file was submitted correctly
  676.      * @access public
  677.      */
  678.     function isValid()
  679.     {
  680.         if ($this->upload['error'] === null) {
  681.             return true;
  682.         }
  683.         return false;
  684.     }
  685.  
  686.     /**
  687.      * User haven't submit a file
  688.      *
  689.      * @return bool If the user submitted a file or not
  690.      * @access public
  691.      */
  692.     function isMissing()
  693.     {
  694.         if ($this->upload['error'] == 'NO_USER_FILE') {
  695.             return true;
  696.         }
  697.         return false;
  698.     }
  699.  
  700.     /**
  701.      * Some error occured during upload (most common due a file size problem,
  702.      * like max size exceeded or 0 bytes long).
  703.      * @return bool If there were errors submitting the file (probably
  704.      *              because the file excess the max permitted file size)
  705.      * @access public
  706.      */
  707.     function isError()
  708.     {
  709.         if (in_array($this->upload['error'], array('TOO_LARGE', 'BAD_FORM','DEV_NO_DEF_FILE'))) {
  710.             return true;
  711.         }
  712.         return false;
  713.     }
  714.  
  715.     /**
  716.      * Moves the uploaded file to its destination directory.
  717.      *
  718.      * @param    string  $dir_dest  Destination directory
  719.      * @param    bool    $overwrite Overwrite if destination file exists?
  720.      * @return   mixed   True on success or Pear_Error object on error
  721.      * @access public
  722.      */
  723.     function moveTo($dir_dest, $overwrite = true)
  724.     {
  725.         if (!$this->isValid()) {
  726.             return $this->raiseError($this->upload['error']);
  727.         }
  728.  
  729.         //Valid extensions check
  730.         if (!$this->_evalValidExtensions()) {
  731.             return $this->raiseError('NOT_ALLOWED_EXTENSION');
  732.         }
  733.  
  734.         $err_code = $this->_chk_dir_dest($dir_dest);
  735.         if ($err_code !== false) {
  736.             return $this->raiseError($err_code);
  737.         }
  738.         // Use 'safe' mode by default if no other was selected
  739.         if (!$this->mode_name_selected) {
  740.             $this->setName('safe');
  741.         }
  742.  
  743.         $name_dest = $dir_dest . DIRECTORY_SEPARATOR . $this->upload['name'];
  744.  
  745.         if (@is_file($name_dest)) {
  746.             if ($overwrite !== true) {
  747.                 return $this->raiseError('FILE_EXISTS');
  748.             } elseif (!is_writable($name_dest)) {
  749.                 return $this->raiseError('CANNOT_OVERWRITE');
  750.             }
  751.         }
  752.  
  753.         // copy the file and let php clean the tmp
  754.         if (!@move_uploaded_file($this->upload['tmp_name'], $name_dest)) {
  755.             return $this->raiseError('E_FAIL_MOVE');
  756.         }
  757.         @chmod($name_dest, $this->_chmod);
  758.         return $this->getProp('name');
  759.     }
  760.  
  761.     /**
  762.      * Check for a valid destination dir
  763.      *
  764.      * @param    string  $dir_dest Destination dir
  765.      * @return   mixed   False on no errors or error code on error
  766.      */
  767.     function _chk_dir_dest($dir_dest)
  768.     {
  769.         if (!$dir_dest) {
  770.             return 'MISSING_DIR';
  771.         }
  772.         if (!@is_dir ($dir_dest)) {
  773.             return 'IS_NOT_DIR';
  774.         }
  775.         if (!is_writeable ($dir_dest)) {
  776.             return 'NO_WRITE_PERMS';
  777.         }
  778.         return false;
  779.     }
  780.     /**
  781.      * Retrive properties of the uploaded file
  782.      * @param string $name   The property name. When null an assoc array with
  783.      *                       all the properties will be returned
  784.      * @return mixed         A string or array
  785.      * @see HTTP_Upload_File::HTTP_Upload_File()
  786.      * @access public
  787.      */
  788.     function getProp($name = null)
  789.     {
  790.         if ($name === null) {
  791.             return $this->upload;
  792.         }
  793.         return $this->upload[$name];
  794.     }
  795.  
  796.     /**
  797.      * Returns a error message, if a error occured
  798.      * (deprecated) Use getMessage() instead
  799.      * @return string    a Error message
  800.      * @access public
  801.      */
  802.     function errorMsg()
  803.     {
  804.         return $this->errorCode($this->upload['error']);
  805.     }
  806.  
  807.     /**
  808.      * Returns a error message, if a error occured
  809.      * @return string    a Error message
  810.      * @access public
  811.      */
  812.     function getMessage()
  813.     {
  814.         return $this->errorCode($this->upload['error']);
  815.     }
  816.  
  817.     /**
  818.      * Function to restrict the valid extensions on file uploads
  819.      *
  820.      * @param array $exts File extensions to validate
  821.      * @param string $mode The type of validation:
  822.      *                       1) 'deny'   Will deny only the supplied extensions
  823.      *                       2) 'accept' Will accept only the supplied extensions
  824.      *                                   as valid
  825.      * @access public
  826.      */
  827.     function setValidExtensions($exts, $mode = 'deny')
  828.     {
  829.         $this->_extensions_check = $exts;
  830.         $this->_extensions_mode  = $mode;
  831.     }
  832.  
  833.     /**
  834.      * Evaluates the validity of the extensions set by setValidExtensions
  835.      *
  836.      * @return bool False on non valid extension, true if they are valid
  837.      * @access private
  838.      */
  839.     function _evalValidExtensions()
  840.     {
  841.         $exts = $this->_extensions_check;
  842.         settype($exts, 'array');
  843.         if ($this->_extensions_mode == 'deny') {
  844.             if (in_array($this->getProp('ext'), $exts)) {
  845.                 return false;
  846.             }
  847.         // mode == 'accept'
  848.         } else {
  849.             if (!in_array($this->getProp('ext'), $exts)) {
  850.                 return false;
  851.             }
  852.         }
  853.         return true;
  854.     }
  855. }
  856. ?>